﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.DirectX;
using Sanford.Multimedia.Midi;
using Microsoft.DirectX.Direct3D;

namespace BurningSphere.Simulator.Controls
{
	public class MidiControlBase : LaserControl
	{
		int channel;
		Matrix laserMatrix;

		protected float x, y;

		/// <summary>
		/// Update method
		/// </summary>
		/// <param name="matrix"></param>
		public override void Update(Matrix matrix)
		{
			TargetXY(matrix);
		}

		/// <summary>
		/// Final matrix
		/// </summary>
		public override Matrix LaserMatrix
		{
			get
			{
				return laserMatrix;
			}
		}

		/// <summary>
		/// MIDI channel
		/// </summary>
		public int Channel
		{
			get
			{
				return channel;
			}
			set
			{
				channel = value;
			}
		}

		/// <summary>
		/// For iterating through whatever animation or
		/// sequence the subclass presents
		/// </summary>
		/// <returns></returns>
		public override bool MoveNext()
		{
			return true;
		}

		/// <summary>
		/// Called immediately after the control has been
		/// loaded and the properties set.
		/// </summary>
		public override void OnLoad()
		{
			Form1.Midi.Device.ChannelMessageReceived += new EventHandler<Sanford.Multimedia.Midi.ChannelMessageEventArgs>(MidiDeviceChannelMessageReceived);
		}

		/// <summary>
		/// Received
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void MidiDeviceChannelMessageReceived(object sender, Sanford.Multimedia.Midi.ChannelMessageEventArgs e)
		{
			if (e.Message.MidiChannel != Channel)
			{
				return;
			}
			OnMidiChannelMessageReceived(e.Message);
		}

		/// <summary>
		/// Virtual method for handling MIDI channel events
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnMidiChannelMessageReceived(ChannelMessage message)
		{
			switch (message.Command)
			{
				case ChannelCommand.NoteOff:
					OnNoteOff();
					break;
				case ChannelCommand.NoteOn:
					OnNoteOn(message.Data1, message.Data2);
					break;
				case ChannelCommand.Controller:
					OnControllerEvent(message.Data1, message.Data2);
					break;
			}
		}

		/// <summary>
		/// Note off event
		/// </summary>
		protected virtual void OnNoteOff()
		{
		}

		/// <summary>
		/// Note on event
		/// </summary>
		/// <param name="note"></param>
		protected virtual void OnNoteOn(int note, int velocity)
		{
		}

		/// <summary>
		/// On controller event
		/// </summary>
		/// <param name="controllerIndex"></param>
		/// <param name="controllerValue"></param>
		protected virtual void OnControllerEvent(int controllerIndex, int controllerValue)
		{
		}

		/// <summary>
		/// Utility function for converting the X and Y values to a matrix
		/// </summary>
		/// <param name="matrix"></param>
		protected void TargetXY(Matrix matrix)
		{
			Matrix rotateY = Matrix.RotationY(Geometry.DegreeToRadian(x) * 180.0f);
			Matrix rotateX = Matrix.RotationX(Geometry.DegreeToRadian(y) * 180.0f);
			laserMatrix = rotateX * rotateY * matrix;
		}
	}
}
